#!/usr/bin/env python3
"""
用户自定义定时任务执行引擎
专门用于执行用户自定义的Python脚本，不包含钉钉消息发送功能
"""

import subprocess
import sys
import os
import logging
from datetime import datetime
from typing import Dict, Any, Optional

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('CustomTaskEngine')
logger.setLevel(logging.DEBUG)

class CustomTaskEngine:
    """用户自定义定时任务执行引擎"""
    
    def __init__(self):
        pass
    
    def execute_script(self, script_path: str, task_id: int) -> bool:
        """
        执行用户自定义Python脚本
        :param script_path: 脚本文件路径
        :param task_id: 任务ID
        :return: 是否执行成功
        """
        task = None
        execution_log = None
        try:
            # 添加项目根目录到路径的最前面，确保能够正确导入user_parameters等模块
            root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            if root_dir not in sys.path:
                sys.path.insert(0, root_dir)
                logger.info(f"已添加项目根目录到Python路径: {root_dir}")
            
            # 直接从models模块导入所需的类，避免从app模块导入
            from models import db, CustomTask, CustomTaskLog
            
            # 查找任务
            task = CustomTask.query.get(task_id)
            if not task:
                logger.error(f"找不到用户自定义定时任务: task_id={task_id}")
                return False
            
            # 检查脚本文件是否存在
            if not os.path.exists(script_path):
                logger.error(f"脚本文件不存在: {script_path}")
                return False
            
            # 创建执行日志（只有任务存在时才创建）
            start_time = datetime.now()
            if task and task.id:
                execution_log = CustomTaskLog(
                    task_id=task_id,
                    start_time=start_time,
                    status='运行中'
                )
                db.session.add(execution_log)
                db.session.commit()
                task.last_run_time = start_time
                db.session.commit()
            else:
                logger.warning(f"任务不存在，跳过日志创建: task_id={task_id}")
                return False
            
            logger.info(f"开始执行用户自定义定时任务: {task.name}")
            
            # 执行脚本
            cmd = [sys.executable, script_path]
            
            # 设置环境变量，确保脚本能找到user_parameters模块
            env = os.environ.copy()
            env['PYTHONPATH'] = root_dir + os.pathsep + env.get('PYTHONPATH', '')
            logger.info(f"设置PYTHONPATH环境变量: {env['PYTHONPATH']}")
            
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                env=env  # 使用修改后的环境变量
            )
            
            end_time = datetime.now()
            duration = (end_time - start_time).total_seconds()
            
            # 更新执行日志
            if execution_log:
                execution_log.end_time = end_time
                execution_log.duration = duration
                execution_log.output = result.stdout
                execution_log.error_message = result.stderr
            
            # 判断执行状态
            if result.returncode == 0:
                if execution_log:
                    execution_log.status = '成功'
                task.last_run_status = '成功'
                logger.info(f"用户自定义定时任务执行成功: {task.name}")
            else:
                if execution_log:
                    execution_log.status = '失败'
                task.last_run_status = '失败'
                logger.error(f"用户自定义定时任务执行失败: {task.name}, 返回码: {result.returncode}")
            
            # 更新任务信息
            task.last_run_duration = duration
            
            db.session.commit()
            logger.info(f"用户自定义定时任务执行完成: {task.name}, 耗时: {duration}秒")
            
            return result.returncode == 0
            
        except Exception as e:
            logger.error(f"执行用户自定义定时任务失败: {str(e)}")
            if task:
                task.last_run_status = '失败'
                db.session.commit()
            return False
    
    def validate_script(self, script_path: str) -> tuple[bool, str]:
        """
        验证脚本文件是否有效
        :param script_path: 脚本文件路径
        :return: (是否有效, 错误信息)
        """
        try:
            # 检查文件是否存在
            if not os.path.exists(script_path):
                return False, "脚本文件不存在"
            
            # 检查文件扩展名
            if not script_path.endswith('.py'):
                return False, "只支持Python脚本文件(.py)"
            
            # 检查文件大小
            file_size = os.path.getsize(script_path)
            if file_size > 1024 * 1024:  # 1MB限制
                return False, "脚本文件过大（超过1MB）"
            
            # 尝试编译脚本（语法检查）
            with open(script_path, 'r', encoding='utf-8') as f:
                script_content = f.read()
            
            compile(script_content, script_path, 'exec')
            
            return True, "脚本验证通过"
            
        except SyntaxError as e:
            return False, f"脚本语法错误: {str(e)}"
        except Exception as e:
            return False, f"脚本验证失败: {str(e)}"
    
    def get_script_info(self, script_path: str) -> Dict[str, Any]:
        """
        获取脚本文件信息
        :param script_path: 脚本文件路径
        :return: 脚本信息字典
        """
        try:
            if not os.path.exists(script_path):
                return {"error": "文件不存在"}
            
            stat = os.stat(script_path)
            
            # 读取文件内容的前几行作为预览
            with open(script_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()
                preview = ''.join(lines[:10])  # 前10行
            
            return {
                "size": stat.st_size,
                "modified_time": datetime.fromtimestamp(stat.st_mtime),
                "preview": preview,
                "line_count": len(lines)
            }
            
        except Exception as e:
            return {"error": str(e)}

if __name__ == '__main__':
    # 测试用法
    engine = CustomTaskEngine()
    
    # 测试脚本验证
    test_script = "custom_scripts/example_script.py"
    if os.path.exists(test_script):
        is_valid, message = engine.validate_script(test_script)
        print(f"脚本验证结果: {is_valid}, 消息: {message}")
        
        if is_valid:
            info = engine.get_script_info(test_script)
            print(f"脚本信息: {info}")
    else:
        print(f"测试脚本不存在: {test_script}")